#lang scheme

(provide align-down
         align-up
         align-gap-down
         align-gap-up
         )

(require "test.ss")

(define (align-down x mod)
  (- x (modulo x mod)))

(define (align-up x mod)
  (+ x (modulo (- mod x) mod)))

(define (align-gap-down x mod)
  (modulo x mod))

(define (align-gap-up x mod)
  (modulo (- mod x) mod))

; +TEST
(define (test x mod)
  (true! (or (= mod (+ (align-gap-down x mod) (align-gap-up x mod)))
             (= 0 (+ (align-gap-down x mod) (align-gap-up x mod)))))
  (=! x (+ (align-down x mod) (align-gap-down x mod)))
  (=! x (- (align-up x mod) (align-gap-up x mod)))
  (list (align-down x mod) 
        (align-gap-down x mod) 
        (align-up x mod)
        (align-gap-up x mod)))

(equal! (test (- #x1001) #x1000)  (list (- #x2000) #x0FFF (- #x1000)      1))
(equal! (test (- #x1000) #x1000)  (list (- #x1000)      0 (- #x1000)      0))
(equal! (test (- #x0FFF) #x1000)  (list (- #x1000)      1         0  #x0FFF))
(equal! (test         -1 #x1000)  (list (- #x1000) #x0FFF         0       1))
(equal! (test          0 #x1000)  (list          0      0         0       0))
(equal! (test          1 #x1000)  (list          0      1    #x1000  #x0FFF))
(equal! (test     #x0FFF #x1000)  (list          0 #x0FFF    #x1000       1))
(equal! (test     #x1000 #x1000)  (list     #x1000      0    #x1000       0))
(equal! (test     #x1001 #x1000)  (list     #x1000      1    #x2000  #x0FFF))
(equal! (test     #x1FFF #x1000)  (list     #x1000 #x0FFF    #x2000       1))
(equal! (test     #x2000 #x1000)  (list     #x2000      0    #x2000       0))
(equal! (test     #x2001 #x1000)  (list     #x2000      1    #x3000  #x0FFF))
